home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-04 / gs24src.zip / STREAM.C < prev    next >
C/C++ Source or Header  |  1992-03-05  |  12KB  |  432 lines

  1. /* Copyright (C) 1989, 1992 Aladdin Enterprises.  All rights reserved.
  2.    Distributed by Free Software Foundation, Inc.
  3.  
  4. This file is part of Ghostscript.
  5.  
  6. Ghostscript is distributed in the hope that it will be useful, but
  7. WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
  8. to anyone for the consequences of using it or for whether it serves any
  9. particular purpose or works at all, unless he says so in writing.  Refer
  10. to the Ghostscript General Public License for full details.
  11.  
  12. Everyone is granted permission to copy, modify and redistribute
  13. Ghostscript, but only under the conditions described in the Ghostscript
  14. General Public License.  A copy of this license is supposed to have been
  15. given to you along with Ghostscript so you can know your rights and
  16. responsibilities.  It should be in a file named COPYING.  Among other
  17. things, the copyright notice and this notice must be preserved on all
  18. copies.  */
  19.  
  20. /* stream.c */
  21. /* Stream package for Ghostscript interpreter */
  22. #include <stdio.h>
  23. #include "memory_.h"
  24. #include "std.h"
  25. #include "stream.h"
  26. #include "scanchar.h"
  27.  
  28. /* Forward declarations */
  29.     /* Generic */
  30. /* Export these for filters */
  31. void
  32.   s_std_init(P5(stream *, byte *, uint, stream_procs *, int /*mode*/));
  33. int
  34.   s_std_null(P1(stream *)),
  35.   s_std_noavailable(P2(stream *, long *)),
  36.   s_std_close(P1(stream *));
  37.     /* Strings */
  38. private int
  39.   s_string_read_buf(P1(stream *)),
  40.   s_string_write_buf(P1(stream *)),
  41.   s_string_available(P2(stream *, long *)),
  42.   s_string_seek(P2(stream *, long));
  43. private void
  44.   s_string_init(P4(stream *, byte *, uint, stream_procs *));
  45.     /* Files */
  46. private int
  47.   s_file_read_buf(P1(stream *)),
  48.   s_file_available(P2(stream *, long *)),
  49.   s_file_read_seek(P2(stream *, long)),
  50.   s_file_read_close(P1(stream *));
  51. private int
  52.   s_file_write_buf(P1(stream *)),
  53.   s_file_write_seek(P2(stream *, long)),
  54.   s_file_write_flush(P1(stream *)),
  55.   s_file_write_close(P1(stream *));
  56.  
  57. /* ------ Generic procedures ------ */
  58.  
  59. /* Standard stream initialization */
  60. void
  61. s_std_init(register stream *s, byte *ptr, uint len, stream_procs *pp,
  62.   int mode)
  63. {    s->cbuf = ptr;
  64.     s->cptr = ptr - 1;
  65.     s->endptr = (mode == s_mode_write ? s->cptr + len : s->cptr);
  66.     s->mode = mode;
  67.     s->end_status = 0;
  68.     s->bsize = s->cbsize = len;
  69.     s->strm = 0;            /* not a filter */
  70.     s->procs = *pp;
  71. }
  72.  
  73. /* Implement a stream procedure as a no-op. */
  74. int
  75. s_std_null(stream *s)
  76. {    return 0;
  77. }
  78.  
  79. /* Indicate an error when asked for available input bytes. */
  80. int
  81. s_std_noavailable(stream *s, long *pl)
  82. {    return ERRC;
  83. }
  84.  
  85. /* Standard stream finalization.  Disable the stream. */
  86. int
  87. s_std_close(stream *s)
  88. {    s_disable(s);
  89.     return 0;
  90. }
  91. void
  92. s_disable(register stream *s)
  93. {    s->bsize = 0;
  94.     s->mode = 0;
  95.     /****** SHOULD DO MORE THAN THIS ******/
  96. }
  97.  
  98. /* ------ Implementation-independent procedures ------ */
  99.  
  100. /* Implement sgetc when the buffer is empty, */
  101. /* by refilling the buffer and then reading a byte. */
  102. int
  103. spgetc(register stream *s)
  104. {    int code;
  105.     if ( s->end_status ) return s->end_status;
  106.     code = (*s->procs.read_buf)(s);
  107.     if ( code < 0 ) return code;
  108.     if ( sendbufp(s) )
  109.         return (s->end_status ? s->end_status : EOFC);
  110.     return *++(s->cptr);
  111. }
  112.  
  113. /* Implementing sputc when the buffer is full, */
  114. /* by flushing the buffer and then writing the byte. */
  115. int
  116. spputc(register stream *s, byte b)
  117. {    int code;
  118.     if ( s->end_status ) return s->end_status;
  119.     code = (*s->procs.write_buf)(s);
  120.     if ( code < 0 ) return code;
  121.     return sputc(s, b);
  122. }
  123.  
  124. /* Push back a character onto a (read) stream. */
  125. /* Return 0 on success, ERRC on failure. */
  126. int
  127. sungetc(register stream *s, byte c)
  128. {    if ( !s_is_reading(s) || s->cptr < s->cbuf ) return ERRC;
  129.     *(s->cptr)-- = c;
  130.     return 0;
  131. }
  132.  
  133. /* Read a string from a stream. */
  134. /* Return the number of bytes read. */
  135. uint
  136. sgets(register stream *s, byte *str, uint rlen)
  137. {    uint len = rlen;
  138.     while ( len > 0 )
  139.        {    uint count = sbufavailable(s);
  140.         if ( count == 0 )
  141.            {    int code;
  142.             if ( s->end_status )
  143.                 return rlen - len;
  144.             code = (*s->procs.read_buf)(s);
  145.             if ( code < 0 || sendbufp(s) )
  146.                 return rlen - len;
  147.             continue;
  148.            }
  149.         if ( count > len ) count = len;
  150.         memcpy(str, s->cptr + 1, count);
  151.         s->cptr += count;
  152.         str += count;
  153.         len -= count;
  154.        }
  155.     return rlen;
  156. }
  157.  
  158. /* Write a string on a stream. */
  159. /* Return the number of bytes written. */
  160. uint
  161. sputs(register stream *s, const byte *str, uint wlen)
  162. {    uint len = wlen;
  163.     if ( wlen > s->bsize && s->procs.write_buf == s_file_write_buf )
  164.        {    /* Write directly on the file. */
  165.         uint write_count;
  166.         (*s->procs.write_buf)(s);
  167.         write_count = fwrite(str, 1, wlen, s->file);
  168.         if ( s->position >= 0 )        /* file is positionable */
  169.             s->position = ftell(s->file);
  170.         return write_count;
  171.        }
  172.     while ( len > 0 )
  173.        {    uint count = sbufavailable(s);
  174.         if ( count > 0 )
  175.            {    if ( count > len ) count = len;
  176.             memcpy(s->cptr + 1, str, count);
  177.             s->cptr += count;
  178.             str += count;
  179.             len -= count;
  180.            }
  181.         else
  182.            {    byte ch = *str++;
  183.             sputc(s, ch);
  184.             if ( s->end_status ) return wlen - len;
  185.             len--;
  186.            }
  187.        }
  188.     return wlen;
  189. }
  190.  
  191. /* Read a hex string from a stream. */
  192. /* Answer EOFC if we reached end-of-file before filling the string, */
  193. /* 0 if we filled the string first, or ERRC on error. */
  194. /* *odd_digit should be -1 initially: */
  195. /* if an odd number of hex digits was read, *odd_digit is set to */
  196. /* the odd digit value, otherwise *odd_digit is set to -1. */
  197. /* If ignore_garbage is true, characters other than hex digits are ignored; */
  198. /* if ignore_garbage is false, characters other than hex digits or */
  199. /* whitespace return an error. */
  200. int
  201. sreadhex(stream *s, byte *str, uint rlen, uint *nread,
  202.   int *odd_digit, int ignore_garbage)
  203. {    byte *ptr = str;
  204.     byte *limit = ptr + rlen;
  205.     byte val1 = (byte)*odd_digit;
  206.     byte val2;
  207.     byte save_last;
  208.     register byte _ds *decoder = scan_char_decoder;
  209.     register byte *sptr, *endp;
  210.     int ch;
  211.     int code;
  212. #define begin_inline(sptr, endp, s)\
  213.   (sptr = s->cptr, endp = s->endptr - 1)
  214. #define sgetc_inline(sptr, endp, s)\
  215.   (sptr <= endp ? *++sptr :\
  216.    (end_inline(sptr, s), ch = spgetc(s), begin_inline(sptr, endp, s), ch))
  217. #define end_inline(sptr, s)\
  218.   (s->cptr = sptr)
  219.     if ( rlen == 0 )
  220.        {    *nread = 0;
  221.         return 0;
  222.        }
  223.     begin_inline(sptr, endp, s);
  224.     if ( val1 <= 0xf ) goto d2;
  225. d1:    /* Fast check for common case */
  226.     if ( sptr >= endp ) goto x1;    /* no last char to save */
  227.     save_last = *endp;
  228.     *endp = ' ';            /* force exit from fast loop */
  229. f1:    if ( (val1 = decoder[sptr[1]]) <= 0xf &&
  230.          (val2 = decoder[sptr[2]]) <= 0xf
  231.        )
  232.        {    sptr += 2;
  233.         *ptr++ = (val1 << 4) + val2;
  234.         if ( ptr < limit ) goto f1;
  235.         *endp = save_last;
  236.         goto px;
  237.        }
  238.     *endp = save_last;
  239. x1:    while ( (val1 = decoder[sgetc_inline(sptr, endp, s)]) > 0xf )
  240.        {    if ( val1 == ctype_eof )
  241.            {    code = ch; *odd_digit = -1; goto ended;    }
  242.         else if ( val1 != ctype_space && !ignore_garbage )
  243.            {    sptr--; *odd_digit = -1; goto err;    }
  244.        }
  245. d2:    while ( (val2 = decoder[sgetc_inline(sptr, endp, s)]) > 0xf )
  246.        {    if ( val2 == ctype_eof )
  247.            {    code = ch; *odd_digit = val1; goto ended;    }
  248.         else if ( val2 != ctype_space && !ignore_garbage )
  249.            {    sptr--; *odd_digit = val1; goto err;    }
  250.        }
  251.     *ptr++ = (val1 << 4) + val2;
  252.     if ( ptr < limit ) goto d1;
  253. px:    *nread = rlen;
  254.     end_inline(sptr, s);
  255.     return 0;
  256. err:    code = ERRC;
  257. ended:    *nread = ptr - str;
  258.     end_inline(sptr, s);
  259.     return code;
  260. }
  261.  
  262. /* ------ String streams ------ */
  263.  
  264. /* Initialize a stream for reading a string. */
  265. void
  266. sread_string(register stream *s, byte *ptr, uint len)
  267. {    static stream_procs p =
  268.        {    s_string_available, s_string_seek, s_std_null, s_std_null,
  269.         s_string_read_buf, NULL
  270.        };
  271.     s_string_init(s, ptr, len, &p);
  272.     s->mode = s_mode_read;
  273. }
  274. /* Handle end-of-buffer when reading from a string. */
  275. private int
  276. s_string_read_buf(stream *s)
  277. {    s->cptr = s->endptr;
  278.     s->end_status = EOFC;
  279.     return EOFC;
  280. }
  281. /* Return the number of available bytes when reading from a string. */
  282. private int
  283. s_string_available(stream *s, long *pl)
  284. {    *pl = sbufavailable(s);
  285.     if ( *pl == 0 ) *pl = -1;    /* EOF */
  286.     return 0;
  287. }
  288.  
  289. /* Initialize a stream for writing a string. */
  290. void
  291. swrite_string(register stream *s, byte *ptr, uint len)
  292. {    static stream_procs p =
  293.        {    s_std_noavailable, s_string_seek, s_std_null, s_std_null,
  294.         NULL, s_string_write_buf
  295.        };
  296.     s_string_init(s, ptr, len, &p);
  297.     s->mode = s_mode_write;
  298. }
  299. /* Handle end-of-buffer when writing a string. */
  300. private int
  301. s_string_write_buf(stream *s)
  302. {    s->cptr = s->endptr;
  303.     s->end_status = EOFC;
  304.     return EOFC;
  305. }
  306.  
  307. /* Seek in a string.  Return 0 if OK, ERRC if not. */
  308. private int
  309. s_string_seek(register stream *s, long pos)
  310. {    if ( pos < 0 || pos > s->bsize ) return ERRC;
  311.     s->cptr = s->cbuf + pos - 1;
  312.     return 0;
  313. }
  314.  
  315. /* Private initialization */
  316. private void
  317. s_string_init(register stream *s, byte *ptr, uint len, stream_procs *p)
  318. {    s_std_init(s, ptr, len, p, s_mode_write);
  319.     s->end_status = EOFC;        /* this is all there is */
  320.     s->position = 0;
  321.     s->file = 0;            /* not a file stream */
  322. }
  323.  
  324. /* ------ File streams ------ */
  325.  
  326. /* Initialize a stream for reading an OS file. */
  327. void
  328. sread_file(register stream *s, FILE *file, byte *buf, uint len)
  329. {    static stream_procs p =
  330.        {    s_file_available, s_file_read_seek,
  331.         s_std_null, s_file_read_close,
  332.         s_file_read_buf, NULL
  333.        };
  334.     s_std_init(s, buf, len, &p, s_mode_read);
  335.     s->file = file;
  336.     s->position = (file == stdin ? -1 : 0);
  337. }
  338. /* Procedures for reading from a file */
  339. private int
  340. s_file_read_buf(register stream *s)
  341. {    int nread;
  342.     if ( s->position >= 0 )        /* file is positionable */
  343.         s->position = ftell(s->file);
  344.     nread = fread(s->cbuf, 1, s->bsize, s->file);
  345.     s->cptr = s->cbuf - 1;
  346.     s->end_status = (ferror(s->file) ? ERRC : feof(s->file) ? EOFC : 0);
  347.     if ( nread <= 0 ) nread = 0;
  348.     s->endptr = s->cptr + nread;
  349.     return 0;
  350. }
  351. private int
  352. s_file_available(register stream *s, long *pl)
  353. {    *pl = sbufavailable(s);
  354.     if ( sseekable(s) )
  355.        {    long pos, end;
  356.         pos = ftell(s->file);
  357.         if ( fseek(s->file, 0L, 2) ) return ERRC;
  358.         end = ftell(s->file);
  359.         if ( fseek(s->file, pos, 0) ) return ERRC;
  360.         *pl += end - pos;
  361.         if ( *pl == 0 ) *pl = -1;    /* EOF */
  362.        }
  363.     else
  364.        {    if ( *pl == 0 && feof(s->file) ) *pl = -1;    /* EOF */
  365.        }
  366.     return 0;
  367. }
  368. private int
  369. s_file_read_seek(register stream *s, long pos)
  370. {    uint end = s->endptr - s->cbuf + 1;
  371.     long offset = pos - s->position;
  372.     if ( offset >= 0 && offset <= end )
  373.        {    /* Staying within the same buffer */
  374.         s->cptr = s->cbuf + offset - 1;
  375.         return 0;
  376.        }
  377.     if ( fseek(s->file, pos, 0) != 0 )
  378.         return ERRC;
  379.     s->endptr = s->cptr = s->cbuf - 1;
  380.     s->end_status = 0;
  381.     return 0;
  382. }
  383. private int
  384. s_file_read_close(stream *s)
  385. {    return fclose(s->file);
  386. }
  387.  
  388. /* Initialize a stream for writing an OS file. */
  389. void
  390. swrite_file(register stream *s, FILE *file, byte *buf, uint len)
  391. {    static stream_procs p =
  392.        {    s_std_noavailable, s_file_write_seek,
  393.         s_file_write_flush, s_file_write_close,
  394.         NULL, s_file_write_buf
  395.        };
  396.     s_std_init(s, buf, len, &p, s_mode_write);
  397.     s->file = file;
  398.     s->position = (file == stdout || file == stderr ? -1 : 0);
  399.    }
  400. /* Procedures for writing on a file */
  401. private int
  402. s_file_write_buf(register stream *s)
  403. {    uint count = s->cptr + 1 - s->cbuf;
  404.     uint write_count = fwrite(s->cbuf, 1, count, s->file);
  405.     if ( s->position >= 0 )        /* file is positionable */
  406.         s->position = ftell(s->file);
  407.     s->cptr = s->cbuf - 1;
  408.     if ( write_count != count )
  409.        {    s->end_status = (ferror(s->file) ? ERRC : EOFC);
  410.         s->endptr = s->cptr;
  411.        }
  412.     else
  413.         s->endptr = s->cptr + s->bsize;
  414.     return 0;
  415. }
  416. private int
  417. s_file_write_seek(stream *s, long pos)
  418. {    /* Output files are not positionable */
  419.     return ERRC;
  420. }
  421. private int
  422. s_file_write_flush(register stream *s)
  423. {    int result = s_file_write_buf(s);
  424.     fflush(s->file);
  425.     return result;
  426. }
  427. private int
  428. s_file_write_close(register stream *s)
  429. {    s_file_write_buf(s);
  430.     return fclose(s->file);
  431. }
  432.